package com.mfz.common.servlet

import com.mfz.common.persistence.Persistence
import com.mfz.common.units.transformToJSONString
import java.sql.ResultSet


class Success : HttpResult(200, "成功") {
	companion object {
		val it = Success()
	}
}

val SUCCESS_NOT_OPENID = HttpResult(207, "成功，但没有OpenId")


class NoSetRequestType : HttpResult(623, "参数类型不正确，请检查")
class NotFoundObject : HttpResult(641, "未找到指定的对象")
class NotAllowOperation : HttpResult(642, "不允许进行此操作")
class AlreadyExists : HttpResult(643, "已经存在相同对象")
class InUse : HttpResult(646, "此对象正在使用中，不能被删除")
class InsufficientBalance : HttpResult(644, "余额不足")
class LackOfNecessaryParameters : HttpResult(609, "缺少必要的参数")
class StockNotEnough : HttpResult(648, "库存数量不足")


val UNKNOWN = HttpResult(999, "未知错误！")
val SUCCESS = HttpResult(200, "成功")
val ERROR_REQUEST = HttpResult(997, "未识别的请求头")
val ERROR_DECRYPT = HttpResult(998, "解密失败")

val UNKNOWN_TYPE = HttpResult(601, "未指定或未知的TYPE值")
val USER_NOT_LOGIN = HttpResult(602, "用户未登录")
val ERROR_PARAMETER = HttpResult(603, "指定的参数无法转换成JSON格式")
val INVALID_TOKEN = HttpResult(605, "无效的token值")
val INVALID_ENCRYPTION = HttpResult(606, "不能理解的加密类型")
val ENCRYPTION_OBJECT_ERROR = HttpResult(607, "加密操作对象生成异常，请检查")
val DATA_STRUCTURE_ERROR = HttpResult(608, "上传的数据结构出现错误，请检查")
val LACK_OF_NECESSARY_PARAMETERS = HttpResult(609, "缺少必要的参数")

val UNSUPPORTED_OPERATION = HttpResult(621, "不支持的操作")
val UNSUPPORTED_REQUEST = HttpResult(622, "当前不支持此请求")
val COMPANY_LOCKING = HttpResult(623, "用户所在企业已经被锁定，请联系管理员")
val NO_OPERATOR_PERMISSION = HttpResult(639, "无此操作权限")
val WRONG_ACCOUNT_OR_PASSWORD = HttpResult(640, "账号名密码错误")
val NOT_FOUND_OBJECT = HttpResult(641, "未找到指定的对象")
val NOT_ALLOW_OPERATION = HttpResult(642, "当前不允许进行此操作")
val INSUFFICIENT_BALANCE = HttpResult(644, "余额不足")
val OPERATOR_FAILURE = HttpResult(645, "由未知原因导致的操作失败")
val IN_USE_NOT_DELETE = HttpResult(646, "此对象正在使用中，不能被删除")
val USER_NOT_ALLOW_OPERATOR_COMPANY = HttpResult(647, "当前登录用户不能对指定的企业进行此操作。")
val COMPANY_TYPE_INVALID = HttpResult(648, "指定的的企业不能进行当前的操作。")

/**
 *  向前台返回的数据结构
 *
 * create by 2019-06-19.
 *
 * @author yimin
 */
open class HttpResult(val code: Int, var message: String) {
	private var builder = StringBuilder("{}")

	private var found = true

	/**
	 * 实际的数据
	 */
	var data: String
		get() = if (builder.length > 2)
			builder.toString()
		else "{\"message\":\"$message\"}"
		set(value) {
			builder = StringBuilder(value)
		}

	fun setMessage(value: String): HttpResult {
		message = value
		return this
	}

	fun clone(): HttpResult {
		val result = HttpResult(code, message)
		result.found = this.found
		result.builder = this.builder

		return result
	}

	private fun getColumnNames(set: ResultSet): Array<String> {
		val rsmd = set.metaData
		val count = rsmd.columnCount
		return Array(count) {
			rsmd.getColumnName(it + 1)
		}
	}

	private fun getListNames(persistence: Persistence): Array<String>? {
		val fields = persistence.factory.fields

		return Array(fields.size) {
			fields[it].name
		}
	}

	/**
	 * 用以将数据库对应的列表字段转成对象发送出去
	 * 如果原有数据,将继续加入
	 *
	 * @param dataName    需要向前台显示的名称
	 * @param set     需要转换的列表
	 * @param columns 需要转换的列表当中某些列
	 * @param columnName  需要向前台显示名称,对应列名称
	 */
	fun addSetToData(dataName: String, set: ResultSet, columns: Array<String>? = null, columnName: Array<String>? = null, other: String = "") {
		val cName = columnName ?: columns ?: getColumnNames(set)
		val cols = columns ?: cName

		addToBuilder(buildString {
			while (set.next()) {
				if (isNotEmpty()) {
					append(",")
				}

				append("{")
				for (i in cols.indices) {
					if (i > 0) {
						append(",")
					}

					append("\"").append(cName[i]).append("\":").append(transformToJSONString(cName[i], set.getObject(cols[i])))
				}
				append("}")
			}

			append(other)

			insert(0, "\":[").insert(0, dataName).insert(0, "\"").append("]")
		})
	}


	/**
	 * 用以将数据库列表字段转成可以向前面发送的数据格式.
	 *
	 * @param dataName    需要向前台显示的名称
	 * @param lists   需要转换的列表
	 * @param columns 需要转换的列表当中某些列
	 * @param columnName  需要向前台显示名称,对应列名称
	 *
	 */
	@Suppress("unused")
	fun addListToData(dataName: String, lists: List<Persistence>, columns: Array<String>? = null, columnName: Array<String>? = null) {
		val cName = columnName ?: columns ?: getListNames(lists.first()) ?: return
		val cols = columns ?: cName

		val tempBuilder = StringBuilder()

		for (item in lists) {
			addJsonToBuilder(tempBuilder, item, cols, cName)
			tempBuilder.append(",")
		}

		if (tempBuilder.isNotEmpty()) {
			tempBuilder.delete(tempBuilder.length - 1, tempBuilder.length)
		}

		tempBuilder.insert(0, "\":[").insert(0, dataName).insert(0, "\"").append("]")

		addToBuilder(tempBuilder.toString())
	}


	private fun addJsonToBuilder(builder: StringBuilder, item: Persistence, columns: Array<String>? = null, columnName: Array<String>?) {
		val cName = columnName ?: columns ?: getListNames(item) ?: return
		val cols = columns ?: cName

		builder.append("{")

		for (i in cols.indices) {
			if (i > 0) {
				builder.append(",")
			}

			builder.append("\"").append(cName[i]).append("\":")
				.append(transformToJSONString(cName[i], item[cols[i]]))
		}

		builder.append("}")
	}


	/**
	 * 用以将一条数据加入至返回列表当中
	 * 如果原有数据,将继续加入
	 *
	 * @param dataName    需要向前台显示的名称
	 * @param set     需要转换的列表
	 * @param columns 需要转换的列表当中某些列
	 * @param columnName  需要向前台显示名称,对应列名称
	 */
	fun addRowToData(dataName: String, set: ResultSet, columns: Array<String>? = null, columnName: Array<String>? = null) {
		val cName = columnName ?: columns ?: getColumnNames(set)
		val cols = columns ?: cName

		addToBuilder(buildString {
			if (isNotEmpty()) {
				append(",")
			}

			append("{")
			for (i in cols.indices) {
				if (i > 0) {
					append(",")
				}

				append("\"").append(cName[i]).append("\":").append(transformToJSONString(cName[i], set.getObject(cols[i])))
			}
			append("}")

			insert(0, "\"$dataName\":")
		})
	}

	/**
	 * 用以将数据库列表字段转成可以向前面发送的数据格式.
	 * 此方法处理单条数据的插入
	 *
	 *
	 * @param name        需要向前台显示的名称
	 * @param persistence 数据对象。
	 * @param columns     需要转换的列表当中某些列
	 * @param columnName  需要向前台显示名称,对应列名称
	 *
	 */
	fun addInfoToData(name: String, persistence: Persistence, columns: Array<String>? = null, columnName: Array<String>? = null): HttpResult {
		val cName = columnName ?: columns ?: getListNames(persistence) ?: return this

		val tempBuilder = StringBuilder().also {
			it.append("\"").append(name).append("\"").append(":")
			addJsonToBuilder(it, persistence, columns, cName)
		}

		addToBuilder(tempBuilder.toString())
		return this
	}

	/**
	 * 用以将数据库列表字段转成可以向前面发送的数据格式.
	 * 此值仅放在DATA的最上面一层
	 *
	 * @param name  需要向前台显示的名称
	 * @param value 值
	 */
	fun put(name: String, value: Any?): HttpResult {
		addToBuilder("\"$name\":${transformToJSONString(name, value)}")
		return this
	}

	fun addToBuilder(value: String): HttpResult {
		with(this.builder) {
			if (length > 2) {
				insert(1, ",").insert(1, value)
			} else {
				insert(1, value)
			}
		}
		found = true

		return this
	}

	override fun toString(): String {
		return "{\"code\":$code,\"data\":${this.builder},\"message\":\"$message\"}"
	}

	override fun equals(other: Any?): Boolean {
		if (other != null && other is HttpResult) {
			return this.code == other.code
		}

		return false
	}

	override fun hashCode(): Int {
		return code
	}
}

